package com.shuiyun.jtt.utils.codec;

import cn.hutool.core.codec.BCD;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.shuiyun.jtt.message.mapping.DataTypeMapping;
import com.shuiyun.jtt.message.schema.Schema;
import com.shuiyun.jtt.utils.ByteUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.nio.charset.Charset;
import java.util.*;
import java.util.function.Function;


/**
 * @program: jtt1078
 * @description: 实体编解码器
 * @author: shuiyun
 * @create: 2022-02-23 17:09
 **/
@Slf4j
public class CoderDecoderUtil {

    private static final Map<DataType, Function<InputData, String>> SET_FUNCTION_MAP = new HashMap<>(16);

    private static final Map<DataType, Function<OutputData, Object>> GET_FUNCTION_MAP = new HashMap<>(16);
    /**
     * BCD 时间格式
     */
    private final static String BCD_DATE_FORMAT = "yyMMddHHmmss";


    // 初始化代码块
    static {
        SET_FUNCTION_MAP.put(DataType.BYTE, CoderDecoderUtil::setByte);
        SET_FUNCTION_MAP.put(DataType.WORD, CoderDecoderUtil::setWord);
        SET_FUNCTION_MAP.put(DataType.DWORD, CoderDecoderUtil::setDword);
        SET_FUNCTION_MAP.put(DataType.QWORD, CoderDecoderUtil::setQword);
        SET_FUNCTION_MAP.put(DataType.BYTES, CoderDecoderUtil::setBytes);
        SET_FUNCTION_MAP.put(DataType.STRING, CoderDecoderUtil::setString);
        SET_FUNCTION_MAP.put(DataType.LIST, CoderDecoderUtil::setList);
        SET_FUNCTION_MAP.put(DataType.OBJ, CoderDecoderUtil::setObj);
        SET_FUNCTION_MAP.put(DataType.BCD, CoderDecoderUtil::setBcd);
        SET_FUNCTION_MAP.put(DataType.BCD8421, CoderDecoderUtil::setBcd8421);
        SET_FUNCTION_MAP.put(DataType.MAP, CoderDecoderUtil::setMap);


        GET_FUNCTION_MAP.put(DataType.BYTE, CoderDecoderUtil::getByte);
        GET_FUNCTION_MAP.put(DataType.WORD, CoderDecoderUtil::getWord);
        GET_FUNCTION_MAP.put(DataType.DWORD, CoderDecoderUtil::getDword);
        GET_FUNCTION_MAP.put(DataType.QWORD, CoderDecoderUtil::getQword);
        GET_FUNCTION_MAP.put(DataType.BYTES, CoderDecoderUtil::getBytes);
        GET_FUNCTION_MAP.put(DataType.STRING, CoderDecoderUtil::getString);
        GET_FUNCTION_MAP.put(DataType.LIST, CoderDecoderUtil::getList);
        GET_FUNCTION_MAP.put(DataType.OBJ, CoderDecoderUtil::getObj);
        GET_FUNCTION_MAP.put(DataType.BCD, CoderDecoderUtil::getBcd);
        GET_FUNCTION_MAP.put(DataType.BCD8421, CoderDecoderUtil::getBcd8421);
        GET_FUNCTION_MAP.put(DataType.MAP, CoderDecoderUtil::getMap);
    }


    public static <T> T byteBuf2Obj(ByteBuf buf, Class<T> clazz) {

        Field[] fields = clazz.getDeclaredFields();
        JSONObject object = new JSONObject();
        for (Field field : fields) {
            // 是否引用FieldValue注解 如果没有引用则跳过
            if (!field.isAnnotationPresent(FieldValue.class)) {
                continue;
            }
            // 判断是否是校验字段
            FieldValue values = field.getAnnotation(FieldValue.class);
            if (values.checkMethod().length > 0 && ignore(object, values.checkMethod())) {
                continue;
            }
            Function<OutputData, Object> function = GET_FUNCTION_MAP.get(values.type());
            OutputData outputData = null;
            if (DataType.OBJ.equals(values.type())) {
                outputData = new OutputData(values, buf, field.getType());
            } else if (DataType.LIST.equals(values.type())) {
                ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
                outputData = new OutputData(values, buf, (Class<?>) parameterizedType.getActualTypeArguments()[0]);
            } else {
                outputData = new OutputData(values, buf);
            }
            try {
                Object value = function.apply(outputData);
                object.put(field.getName(), value);
            } catch (Exception e) {
                log.error("设置字段 {} 失败", field.getName(), e);
            }
        }

        return JSON.parseObject(object.toJSONString(), clazz);
    }

    /**
     * 是否忽略当前字段
     *
     * @param object      数据实体
     * @param checkMethod 校验方法
     * @return 是否忽略 如果返回是 则跳过当前字段
     * @author shuiyun
     * @date 2022/4/18
     */
    private static boolean ignore(JSONObject object, String[] checkMethod) {
        boolean ignore = false;
        switch (checkMethod[1]) {
            case "&!":
                // 按位与 如果当前位置不含某个字段 则返回true 忽略该字段
                int a = object.getInteger(checkMethod[0]);
                int b = Integer.parseInt(checkMethod[2], 16);
                ignore = (a & b) != b;
                break;
            case "&=":
                // 按位与 如果当前位置含某个字段 则返回true 忽略该字段
                int c = object.getInteger(checkMethod[0]);
                int d = Integer.parseInt(checkMethod[2], 16);
                ignore = (c & d) == d;
                break;
            case "=":
                String e = object.getString(checkMethod[0]);
                if (ObjectUtil.isNull(e)) {
                    return true;
                }
                String f = checkMethod[2];
                ignore = e.equals(f);
            case "!=":
                String g = object.getString(checkMethod[0]);
                if (ObjectUtil.isNull(g)) {
                    return true;
                }
                String h = checkMethod[2];
                ignore = !g.equals(h);
            default:
                break;
        }
        return ignore;
    }


    /**
     * 数据实体转bytebuf
     *
     * @param object 输入的数据对象
     * @return bytebuf
     * @Author: shuiyun
     * @Date: 2022-02-25 11:22
     */
    public static ByteBuf obj2ByteBuf(Object object) {
        JSONObject data = JSON.parseObject(JSON.toJSONString(object));
        Field[] fields = object.getClass().getDeclaredFields();
        ByteBuf buffer = Unpooled.buffer();

        for (Field field : fields) {
            // 是否引用FieldValue注解
            if (!field.isAnnotationPresent(FieldValue.class)) {
                continue;
            }
            // 判断是否是校验字段
            FieldValue values = field.getAnnotation(FieldValue.class);
            if (values.checkMethod().length > 0 && ignore(data, values.checkMethod())) {
                continue;
            }
            Function<InputData, String> function = SET_FUNCTION_MAP.get(values.type());
            // 不满足的唯一条件 数据为空 且 忽略为空数据 才不进入判断
            if (ObjectUtil.isNotNull(data.get(field.getName())) || !values.ignore()) {
                if (DataType.OBJ.equals(values.type())) {
                    function.apply(new InputData(values, data.get(field.getName()), buffer, field.getType()));
                } else if (DataType.LIST.equals(values.type())) {
                    ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
                    function.apply(new InputData(values, data.get(field.getName()), buffer, (Class<?>) parameterizedType.getActualTypeArguments()[0]));
                } else {
                    function.apply(new InputData(values, data.get(field.getName()), buffer));
                }
            }
        }
        return buffer;
    }


    private static int getByte(OutputData outputData) {
        return outputData.getBuf().readUnsignedByte();
    }


    private static Object getMap(OutputData outputData) {
        FieldValue fieldValue = outputData.getFieldValue();
        if (fieldValue.length() < 1) {
            throw new RuntimeException("map field length error!!");
        }

        DataTypeMapping mapping = getDataTypeMapping(fieldValue.clazz());
        ByteBuf buf = outputData.getBuf();

        int size = -1;
        // 如果走lengthSize
        if (fieldValue.lengthSize() > 0) {
            size = getLengthSize(outputData.getBuf(), fieldValue.lengthSize());
        }

        Map<String, Object> result = new HashMap<>();
        if (size > -1) {
            for (int i = 0; i < size; i++) {
                addResult(fieldValue, mapping, buf, result);
            }
        } else {
            while (buf.isReadable()) {
                addResult(fieldValue, mapping, buf, result);
            }
        }
        return result;
    }

    /**
     * 解析输入报文 填充返回结果
     *
     * @param fieldValue 注解
     * @param mapping    参数赢输
     * @param buf        输入数据
     * @param result     转换好的数据
     * @author shuiyun
     * @date 2022/5/10 23:01
     */
    private static void addResult(FieldValue fieldValue, DataTypeMapping mapping, ByteBuf buf, Map<String, Object> result) {
        int key = getLength(buf, fieldValue.length());
        Schema schema = mapping.getSchema(key);
        if (ObjectUtil.isNull(schema)) {
            throw new RuntimeException("未注册的Schema：" + key);
        }
        try {
            result.put(key + "", getMap(schema, buf));
        } catch (Exception e) {
            throw new RuntimeException("设置参数：" + key + " 失败");
        }
    }

    private static Object getMap(Schema schema, ByteBuf buf) {
        byte length = buf.readByte();
        switch (schema.getDataType()) {
            case BYTE:
                return buf.readByte();
            case WORD:
                return buf.readUnsignedShort();
            case DWORD:
                return buf.readUnsignedInt();
            case QWORD:
                return buf.readLong();
            case OBJ:
                return byteBuf2Obj(buf, schema.getClazz());
            case BYTES:
                byte[] bytes = new byte[length];
                buf.readBytes(bytes);
                return BCD.bcdToStr(bytes);
            case STRING:
                byte[] bytes2 = new byte[length];
                buf.readBytes(bytes2);
                return new String(bytes2, Charset.forName("GBK"));
            default:
                throw new RuntimeException("暂未扩展其他类型，如果需要可以自行扩展");
        }
    }

    private static Object getBcd8421(OutputData outputData) {
        int length = outputData.getFieldValue().length();
        byte[] bytes = new byte[length];

        outputData.getBuf().readBytes(bytes);
        return ByteUtil.bytes2HexStr(bytes).replaceFirst("^0*", "");
    }

    private static Date getBcd(OutputData outputData) {
        byte[] bytes = new byte[6];
        outputData.getBuf().readBytes(bytes);
        String format = BCD.bcdToStr(bytes);
        return DateUtil.parse(format, BCD_DATE_FORMAT);
    }

    private static Object getObj(OutputData outputData) {
        Class<?> clazz = outputData.getFieldValue().clazz();
        if (clazz == Void.class) {
            clazz = outputData.getClazz();
        }

        // 如果走lengthSize
        if (outputData.getFieldValue().lengthSize() > 0) {
            int length = getLengthSize(outputData.getBuf(), outputData.getFieldValue().lengthSize());
            ByteBuf tempBuf = outputData.getBuf().readSlice(length);
            return byteBuf2Obj(tempBuf, clazz);
        }
        return byteBuf2Obj(outputData.getBuf(), clazz);
    }

    private static List<Object> getList(OutputData outputData) {

        Class<?> clazz = outputData.getFieldValue().clazz();
        if (clazz == Void.class) {
            clazz = outputData.getClazz();
        }
        ByteBuf buf = outputData.getBuf();
        List<Object> list = new ArrayList<>();
        // 如果走长度固定
        if (outputData.getFieldValue().lengthSize() > -1) {
            int length = getLengthSize(buf, outputData.getFieldValue().lengthSize());
            for (int i = 0; i < length; i++) {
                Object o = byteBuf2Obj(buf, clazz);
                list.add(o);
            }
        } else {
            // 如果没有长度固定 则读取完所有数据
            while (buf.readableBytes() > 1) {
                Object o = byteBuf2Obj(buf, clazz);
                list.add(o);
            }
        }


        return list;
    }

    private static String getString(OutputData outputData) {

        FieldValue fieldValue = outputData.getFieldValue();

        // 如果走lengthSize
        if (fieldValue.lengthSize() > 0) {
            int length = getLengthSize(outputData.getBuf(), fieldValue.lengthSize());
            try {
                byte[] bytes = new byte[length];
                outputData.getBuf().readBytes(bytes);
                return new String(bytes, fieldValue.charset()).trim();
            } catch (Exception e) {
                log.error("string error,length is :{}", length, e);
            }
        }
        // 如果走固长
        else if (fieldValue.length() > 0) {
            int length = fieldValue.length();
            byte[] bytes = new byte[length];
            try {
                outputData.getBuf().readBytes(bytes);
                return new String(bytes, fieldValue.charset()).trim();
            } catch (Exception e) {
                log.error("string error,length is :{}", length, e);
            }
        } else {
            ByteBuf buf = outputData.getBuf();
            byte[] content = new byte[buf.readableBytes()];
            buf.readBytes(content);
            try {
                return new String(content, fieldValue.charset()).trim();
            } catch (Exception e) {
                log.error("读取字符串失败", e);
            }
        }
        return null;
    }

    private static byte[] getBytes(OutputData outputData) {
        FieldValue fieldValue = outputData.getFieldValue();

        int length = 0;
        if (fieldValue.lengthSize() > 0) {
            length = getLengthSize(outputData.getBuf(), fieldValue.lengthSize());
        } else if (fieldValue.length() > 0) {
            length = fieldValue.length();
        } else {
            length = outputData.getBuf().readableBytes();
        }
        if (length < 1) {
            return new byte[0];
        }
        byte[] bytes = new byte[length];
        outputData.getBuf().readBytes(bytes);

        return bytes;
    }

    private static Long getQword(OutputData outputData) {
        return outputData.getBuf().readLong();
    }

    private static Integer getDword(OutputData outputData) {
        return outputData.getBuf().readInt();
    }

    private static Integer getWord(OutputData outputData) {
        return outputData.getBuf().readUnsignedShort();
    }


    private static String setByte(InputData inputData) {
        // 如果数据为空 则设置默认值
        if (ObjectUtil.isNull(inputData.getData())) {
            inputData.setData(0);
        }

        if (inputData.getData() instanceof Boolean) {
            if ((boolean) inputData.getData()) {
                inputData.setData(1);
            } else {
                inputData.setData(0);
            }
        }
        inputData.getBuf().writeByte(Integer.parseInt(inputData.getData().toString()));
        return null;
    }

    private static String setWord(InputData inputData) {
        // 如果数据为空 则设置默认值
        if (ObjectUtil.isNull(inputData.getData())) {
            inputData.setData(0);
        }
        inputData.getBuf().writeShort(Integer.parseInt(inputData.getData().toString()));
        return null;
    }

    private static String setDword(InputData inputData) {
        // 如果数据为空 则设置默认值
        if (ObjectUtil.isNull(inputData.getData())) {
            inputData.setData(0);
        }
        inputData.getBuf().writeInt(Integer.parseInt(inputData.getData().toString()));
        return null;
    }

    private static String setQword(InputData inputData) {
        // 如果数据为空 则设置默认值
        if (ObjectUtil.isNull(inputData.getData())) {
            inputData.setData(0);
        }
        inputData.getBuf().writeLong(Long.parseLong(inputData.getData().toString()));
        return null;
    }

    private static String setBytes(InputData inputData) {
        // 如果数据为空 则设置默认值
        if (ObjectUtil.isNull(inputData.getData())) {
            inputData.setData(new byte[0]);
        }
        FieldValue fieldValue = inputData.getFieldValue();


        byte[] data = java.util.Base64.getMimeDecoder().decode(inputData.getData().toString());
        ;

        // 如果需要设置实体长度
        int lengthSize = fieldValue.lengthSize();
        if (lengthSize > 0) {
            setLengthSize(inputData.getBuf(), lengthSize, data.length);
        }

        if (fieldValue.length() > 0) {
            // 判断输入的数据是否超长 超长则进行报错
            if (fieldValue.length() < data.length) {
                throw new RuntimeException("输入的" + fieldValue.desc() + "字段数据超长");
            }
            // 计算需要补偿的数据个数
            int num = fieldValue.length() - data.length;
            ByteBuf buffer = Unpooled.buffer();
            for (int i = 0; i < num; i++) {
                buffer.writeByte(fieldValue.pad());
            }
            buffer.writeBytes(data);
            inputData.getBuf().writeBytes(buffer);
        } else {
            inputData.getBuf().writeBytes(data);
        }

        return null;
    }

    private static String setString(InputData inputData) {
        // 如果数据为空 则设置默认值
        if (ObjectUtil.isNull(inputData.getData())) {
            inputData.setData("");
        }
        FieldValue fieldValue = inputData.getFieldValue();
        byte[] bytes = inputData.getData().toString().getBytes(Charset.forName(fieldValue.charset()));
        int lengthSize = fieldValue.lengthSize();
        // 如果是动态长度 则直接写入
        if (lengthSize > 0) {
            setLengthSize(inputData.getBuf(), lengthSize, bytes.length);
        }
        // 如果是固长字段
        if (fieldValue.length() > 0) {
            if (fieldValue.length() < bytes.length) {
                throw new RuntimeException("fieldValue :{" + fieldValue.length() + "} less than bytes length:{" + bytes.length + "}");
            }
            byte[] temp = ByteUtil.initBytes(fieldValue.length(), (byte) 0);
            System.arraycopy(bytes, 0, temp, 0, bytes.length);
            bytes = temp;
        }
        // 需要判断是否有写入lengthSize
        inputData.getBuf().writeBytes(bytes);
        return null;
    }


    private static String setObj(InputData inputData) {
        Class<?> clazz = inputData.getFieldValue().clazz();
        if (clazz == Void.class) {
            clazz = inputData.getClazz();
        }
        // 如果数据为空 则设置默认值
        if (ObjectUtil.isNull(inputData.getData())) {
            try {
                Object o = clazz.newInstance();
                inputData.setData(o);
            } catch (Exception e) {
                log.error("根据class生成对象实体失败", e);
            }
        }
        Object obj = JSON.parseObject(JSON.toJSONString(inputData.getData()), clazz);
        ByteBuf tempBuf = obj2ByteBuf(obj);
        int lengthSize = inputData.getFieldValue().lengthSize();
        // 如果需要设置实体长度
        if (lengthSize > 0) {
            setLengthSize(inputData.getBuf(), lengthSize, tempBuf.writerIndex());
        }
        inputData.getBuf().writeBytes(tempBuf);
        return null;
    }


    private static String setList(InputData inputData) {

        Class<?> clazz = inputData.getFieldValue().clazz();
        if (clazz == Void.class) {
            clazz = inputData.getClazz();
        }

        // 如果数据为空 则设置默认值
        if (ObjectUtil.isNull(inputData.getData())) {
            inputData.setData(new ArrayList<>());
        }

        FieldValue fieldValue = inputData.getFieldValue();
        List list = (List) inputData.getData();

        int lengthSize = fieldValue.lengthSize();
        if (lengthSize > 0) {
            setLengthSize(inputData.getBuf(), lengthSize, list.size());
        }

        // 如果不含有数据 则跳过
        if (CollectionUtil.isEmpty(list)) {
            return null;
        }
        ByteBuf startBuff = Unpooled.buffer();
        Class<?> finalClazz = clazz;
        list.forEach(tempObj -> {
            Object obj = JSON.parseObject(JSON.toJSONString(tempObj), finalClazz);
            ByteBuf tempBuf = obj2ByteBuf(obj);
            startBuff.writeBytes(tempBuf);
        });
        inputData.getBuf().writeBytes(startBuff);
        return null;
    }

    private static String setBcd(InputData inputData) {
        Date date = null;
        if (inputData.getData() instanceof Date) {
            date = (Date) inputData.getData();
        } else if (inputData.getData() instanceof Long) {
            date = new Date((long) inputData.getData());
        } else {
            date = new Date();
        }
        String data = DateUtil.format(date, BCD_DATE_FORMAT);
        byte[] bytes = BCD.strToBcd(data);
        inputData.getBuf().writeBytes(bytes);
        return null;
    }

    private static String setMap(InputData inputData) {
        FieldValue fieldValue = inputData.getFieldValue();
        if (fieldValue.length() < 1) {
            throw new RuntimeException("map field length error!!");
        }

        // 获取上面的映射类
        DataTypeMapping mapping = getDataTypeMapping(fieldValue.clazz());
        ByteBuf buf = inputData.getBuf();
        Map<String, Object> map = JSON.parseObject(inputData.getData().toString()).getInnerMap();
        // 如果有长度字段 则需要设置长度
        int lengthSize = fieldValue.lengthSize();
        if (lengthSize > 0) {
            setLengthSize(inputData.getBuf(), lengthSize, map.size());
        }
        map.forEach((k, v) -> {
            int key = Integer.parseInt(k);
            //设置key
            setLength(buf, fieldValue.length(), key);
            // 设置值
            Schema schema = mapping.getSchema(key);
            if (ObjectUtil.isNull(schema)) {
                throw new RuntimeException("未知的schema：" + key);
            }
            try {
                setMap(schema, v, buf);
            } catch (Exception e) {
                throw new RuntimeException("设置参数：" + k + " 失败，输入参数：" + v);
            }
        });
        return null;
    }

    private static void setMap(Schema schema, Object value, ByteBuf buf) {
        switch (schema.getDataType()) {
            case BYTE:
                buf.writeByte(DataType.BYTE.length);
                buf.writeByte(Integer.parseInt(value.toString()));
                break;
            case WORD:
                buf.writeByte(DataType.WORD.length);
                buf.writeShort(Integer.parseInt(value.toString()));
                break;
            case DWORD:
                buf.writeByte(DataType.DWORD.length);
                buf.writeInt(Integer.parseInt(value.toString()));
                break;
            case QWORD:
                buf.writeByte(DataType.QWORD.length);
                buf.writeLong(Long.parseLong(value.toString()));
                break;
            case OBJ:
                Object obj = JSON.parseObject(JSON.toJSONString(value), schema.getClazz());
                ByteBuf tempBuf = obj2ByteBuf(obj);
                buf.writeByte(tempBuf.readableBytes());
                buf.writeBytes(tempBuf);
                break;
            case BYTES:
                byte[] bytes = java.util.Base64.getMimeDecoder().decode(value.toString());
                buf.writeByte(bytes.length);
                buf.writeBytes(bytes);
                break;
            case STRING:
                byte[] bytes2 = value.toString().getBytes(Charset.forName("GBK"));
                buf.writeByte(bytes2.length);
                buf.writeBytes(bytes2);
                break;
            default:
                throw new RuntimeException("暂未扩展其他类型，如果需要可以自行扩展");

        }
    }

    private static DataTypeMapping getDataTypeMapping(Class<?> clazz) {
        DataTypeMapping mapping = null;
        try {
            mapping = (DataTypeMapping) clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (ObjectUtil.isNull(mapping)) {
            throw new RuntimeException("获取map类型字段的映射失败");
        }
        return mapping;
    }

    private static String setBcd8421(InputData inputData) {
        String data = inputData.getData().toString();
        int length = inputData.getFieldValue().length();
        if (data.length() < length * 2) {
            data = String.format("%0" + (length * 2) + "d", Long.parseLong(data));
        } else if (data.length() > length * 2) {
            data = data.substring(0, length * 2);
        }
        byte[] bytes = ByteUtil.hexStr2Bytes(data);
        inputData.getBuf().writeBytes(bytes);
        return null;
    }


    /**
     * 设置lengthSize
     *
     * @param buff       读取的buf
     * @param length     数据长度
     * @param lengthSize 数据长度字段的大小
     * @Author: shuiyun
     * @Date: 2022-02-24 11:35
     */
    private static void setLengthSize(ByteBuf buff, int lengthSize, int length) {
        switch (lengthSize) {
            case 1:
                buff.writeByte(length);
                break;
            case 2:
                buff.writeShort(length);
                break;
            case 3:
                buff.writeMedium(length);
                break;
            case 4:
                buff.writeInt(length);
                break;
            default:
                throw new RuntimeException("unsupported lengthSize:" + lengthSize);
        }
    }

    private static void setLength(ByteBuf buff, int length, int value) {
        switch (length) {
            case 1:
                buff.writeByte(value);
                break;
            case 2:
                buff.writeShort(value);
                break;
            case 3:
                buff.writeMedium(value);
                break;
            case 4:
                buff.writeInt(value);
                break;
        }
    }

    private static int getLength(ByteBuf buff, int length) {
        switch (length) {
            case 1:
                return buff.readUnsignedByte();
            case 2:
                return buff.readUnsignedShort();
            case 4:
                return buff.readInt();
        }
        return 0;
    }


    private static int getLengthSize(ByteBuf buff, int lengthSize) {
        int length = 0;
        switch (lengthSize) {
            case 1:
                length = buff.readByte();
                break;
            case 2:
                length = buff.readShort();
                break;
            case 4:
                length = buff.readInt();
                break;
            default:
                throw new RuntimeException("unsupported lengthSize:" + lengthSize);
        }
        return length;
    }
}

